﻿using System.Text.Json;

using zijian666.AnyExtensions;

namespace zijian666.Updater;
partial class RemoteData
{
    /// <summary>
    /// 读取 JSON 时的序列化选项。
    /// 属性名不区分大小写，跳过注释，允许结尾逗号。
    /// </summary>
    private static readonly JsonSerializerOptions READ_OPTIONS = new()
    {
        PropertyNameCaseInsensitive = true,
        ReadCommentHandling = JsonCommentHandling.Skip,
        AllowTrailingCommas = true,
        PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,

    };
    /// <summary>
    /// 从 JSON 字符串或 Url 加载 <see cref="RemoteData"/> 实例。
    /// </summary>
    /// <param name="jsonOrUrl">JSON 字符串或 Url。</param>
    /// <returns>解析得到的 <see cref="LocalData"/> 实例。</returns>
    /// <exception cref="InvalidOperationException">无法解析版本描述文件时抛出。</exception>
    public async ValueTask LoadFromJson(string jsonOrUrl)
    {
        var json = await Helper.ReadString(jsonOrUrl);
        var list = JsonSerializer.Deserialize<List<JsonElement>>(json, READ_OPTIONS)
                   ?? throw new InvalidOperationException("无法解析版本描述文件");

        ReloadData(list.Select(toVersionInfo));

        VersionInfo toVersionInfo(JsonElement element)
        {
            var info = element.Deserialize<VersionInfo>(READ_OPTIONS);
            var names = Enum.GetNames<UpdateMode>();

            foreach (var prop in element.EnumerateObject())
            {
                foreach (var name in names)
                {
                    if (name.EqualsVariableName(prop.Name))
                    {
                        var updateInfo = prop.Value.Deserialize<UpdateInfo>(READ_OPTIONS);
                        if (updateInfo is { Files: not null })
                        {
                            if (info.UpdateInfos is null)
                            {
                                info = info with { UpdateInfos = new Dictionary<UpdateMode, UpdateInfo>() };
                            }
                            info.UpdateInfos[(UpdateMode)Enum.Parse(typeof(UpdateMode), name)] = updateInfo;
                        }
                    }
                }
            }
            return info;
        }
    }
}